﻿/**
************************************************************************************************************************
* @file    CPU_Ltdc.c
* @author  CTY
* @version 1.0
* @date    2020/12/16
* @brief   QSPI FLASH 驱动
************************************************************************************************************************
* @attention
*
*                               版权所有 (c),  2015,  贵阳永青仪电科技有限公司
* \n
* 
@verbatim
    （详细内容）
@endverbatim
* 
************************************************************************************************************************
*/ 
/*====================================================================================================================*/
/*                                                      引用文件                                                      */
/*====================================================================================================================*/
#include "stm32h7xx_hal.h"


/*====================================================================================================================*/
/*                                                      常量定义                                                      */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                     本地宏定义                                                     */
/*====================================================================================================================*/
  
#define QSPI_FLASH_MEM_ADDR         0x90000000

/* W25Q256JV基本信息 */
#define QSPI_FLASH_SIZE     25                      /* Flash大小，2^25 = 32MB*/
#define QSPI_SECTOR_SIZE    (4 * 1024)              /* 扇区大小，4KB */
#define QSPI_PAGE_SIZE      256                     /* 页大小，256字节 */
#define QSPI_END_ADDR       (1 << QSPI_FLASH_SIZE)  /* 末尾地址 */
#define QSPI_FLASH_SIZES    32 * 1024 * 1024         /* Flash大小，2^25 = 32MB*/

/* W25Q256JV相关命令 */
#define WRITE_ENABLE_CMD                        0x06    /* 写使能指令 */
#define READ_ID_CMD2                            0x9F    /* 读取ID命令 */
#define READ_STATUS_REG_CMD                     0x05    /* 读取状态命令 */
#define SUBSECTOR_ERASE_4_BYTE_ADDR_CMD         0x21    /* 32bit地址扇区擦除指令, 4KB */
#define QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD       0x34    /* 32bit地址的4线快速写入命令 */
#define QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD    0xEC    /* 32bit地址的4线快速读取命令 */

#define BLOCK_ERASE_64K_4_BYTE_ADDR_CMD         0xDC    /* 4字节地址，64K扇区 */



#define QSPI_CLK_ENABLE()               __HAL_RCC_QSPI_CLK_ENABLE()
#define QSPI_CLK_DISABLE()              __HAL_RCC_QSPI_CLK_DISABLE()

#define QSPI_MDMA_CLK_ENABLE()          __HAL_RCC_MDMA_CLK_ENABLE()
#define QSPI_FORCE_RESET()              __HAL_RCC_QSPI_FORCE_RESET()
#define QSPI_RELEASE_RESET()            __HAL_RCC_QSPI_RELEASE_RESET()

#define QSPI_CS_PIN                     GPIO_PIN_6
#define QSPI_CS_GPIO_PORT               GPIOG
#define QSPI_CS_GPIO_AF                 GPIO_AF10_QUADSPI

#define QSPI_CLK_PIN                    GPIO_PIN_10
#define QSPI_CLK_GPIO_PORT              GPIOF
#define QSPI_CLK_GPIO_AF                GPIO_AF9_QUADSPI

#define QSPI_BK1_D0_PIN                 GPIO_PIN_8
#define QSPI_BK1_D0_GPIO_PORT           GPIOF
#define QSPI_BK1_D0_GPIO_AF             GPIO_AF10_QUADSPI

#define QSPI_BK1_D1_PIN                 GPIO_PIN_9
#define QSPI_BK1_D1_GPIO_PORT           GPIOF
#define QSPI_BK1_D1_GPIO_AF             GPIO_AF10_QUADSPI

#define QSPI_BK1_D2_PIN                 GPIO_PIN_7
#define QSPI_BK1_D2_GPIO_PORT           GPIOF
#define QSPI_BK1_D2_GPIO_AF             GPIO_AF9_QUADSPI

#define QSPI_BK1_D3_PIN                 GPIO_PIN_6
#define QSPI_BK1_D3_GPIO_PORT           GPIOF
#define QSPI_BK1_D3_GPIO_AF             GPIO_AF9_QUADSPI

/*====================================================================================================================*/
/*                                                  本地数据类型定义                                                  */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                      全局变量                                                      */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                      本地变量                                                      */
/*====================================================================================================================*/

static QSPI_HandleTypeDef QSPIHandle;


/*====================================================================================================================*/
/*                                                    本地函数声明                                                    */
/*====================================================================================================================*/
static int QSPI_MemoryMapped(void);

/*====================================================================================================================*/
/*                                                      全局函数                                                      */
/*====================================================================================================================*/

/**************************************************************************************************/
/**
@brief      初始化
@verbatim   
    （详细描述）
@endverbatim
@param      无
@retval     true=成功，false=失败。
*/
/**************************************************************************************************/
void CPU_QSPI_Init(void)
{
    uint32_t i;
    
    /* 复位QSPI */
    QSPIHandle.Instance = QUADSPI;   
    
    HAL_QSPI_DeInit(&QSPIHandle);

    /* 设置时钟速度，QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
    QSPIHandle.Init.ClockPrescaler = 1;

    /* 设置FIFO阀值，范围1 - 32 */
    QSPIHandle.Init.FifoThreshold = 1;

    /* 
        QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
        在外部信号延迟时，这有利于推迟数据采样。
    */
    QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;

    /* Flash大小是2^(FlashSize + 1) = 2^25 = 32MB */
    QSPIHandle.Init.FlashSize = QSPI_FLASH_SIZE;   //QSPI_FLASH_SIZE - 1; 2020-03-04, 需要扩大一倍，否则内存映射方位最后1个地址时，会异常

    /* 命令之间的CS片选至少保持1个时钟周期的高电平 */
    QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_5_CYCLE;

    /*
       MODE0: 表示片选信号空闲期间，CLK时钟信号是低电平
       MODE3: 表示片选信号空闲期间，CLK时钟信号是高电平
    */
    QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;

    /* QSPI有两个BANK，这里使用的BANK1 */
    QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1;

    /* V7开发板仅使用了BANK1，这里是禁止双BANK */
    QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

    /* 初始化配置QSPI */
    while (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) ;
    
    QSPI_MemoryMapped();
}


void HAL_QSPI_MspInit(QSPI_HandleTypeDef *hqspi)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    /* 使能QPSI时钟  */
    QSPI_CLK_ENABLE();

    /* 复位时钟接口 */
    QSPI_FORCE_RESET();
    QSPI_RELEASE_RESET();    
    
    /* QSPI CS GPIO 引脚配置 */
    GPIO_InitStruct.Pin = QSPI_CS_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = QSPI_CS_GPIO_AF;
    HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &GPIO_InitStruct);

    /* QSPI CLK GPIO 引脚配置 */
    GPIO_InitStruct.Pin = QSPI_CLK_PIN;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Alternate = QSPI_CLK_GPIO_AF;
    HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &GPIO_InitStruct);

    /* QSPI D0 GPIO pin 引脚配置 */
    GPIO_InitStruct.Pin = QSPI_BK1_D0_PIN;
    GPIO_InitStruct.Alternate = QSPI_BK1_D0_GPIO_AF;
    HAL_GPIO_Init(QSPI_BK1_D0_GPIO_PORT, &GPIO_InitStruct);

    /* QSPI D1 GPIO 引脚配置 */
    GPIO_InitStruct.Pin = QSPI_BK1_D1_PIN;
    GPIO_InitStruct.Alternate = QSPI_BK1_D1_GPIO_AF;
    HAL_GPIO_Init(QSPI_BK1_D1_GPIO_PORT, &GPIO_InitStruct);

    /* QSPI D2 GPIO 引脚配置 */
    GPIO_InitStruct.Pin = QSPI_BK1_D2_PIN;
    GPIO_InitStruct.Alternate = QSPI_BK1_D2_GPIO_AF;
    HAL_GPIO_Init(QSPI_BK1_D2_GPIO_PORT, &GPIO_InitStruct);

    /* QSPI D3 GPIO 引脚配置 */
    GPIO_InitStruct.Pin = QSPI_BK1_D3_PIN;
    GPIO_InitStruct.Alternate = QSPI_BK1_D3_GPIO_AF;
    HAL_GPIO_Init(QSPI_BK1_D3_GPIO_PORT, &GPIO_InitStruct);
}

void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi)
{
    /* 复位QSPI引脚 */
    HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN);
    HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN);
    HAL_GPIO_DeInit(QSPI_BK1_D0_GPIO_PORT, QSPI_BK1_D0_PIN);
    HAL_GPIO_DeInit(QSPI_BK1_D1_GPIO_PORT, QSPI_BK1_D1_PIN);
    HAL_GPIO_DeInit(QSPI_BK1_D2_GPIO_PORT, QSPI_BK1_D2_PIN);
    HAL_GPIO_DeInit(QSPI_BK1_D3_GPIO_PORT, QSPI_BK1_D3_PIN);

    /* 复位QSPI */
    QSPI_FORCE_RESET();
    QSPI_RELEASE_RESET();

    /* 关闭QSPI时钟 */
    QSPI_CLK_DISABLE();
}

static int QSPI_MemoryMapped(void)
{
    QSPI_CommandTypeDef s_command = { 0 };
    QSPI_MemoryMappedTypeDef s_mem_mapped_cfg = { 0 };
    

    /* 基本配置 */
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1线方式发送指令 */ 
    s_command.AddressSize = QSPI_ADDRESS_32_BITS; /* 32位地址 */
    s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */
    s_command.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q256JV不支持DDR */
    s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR模式，数据输出延迟 */
    s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输都发指令 */
    
    /* 全部采用4线 */
    s_command.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 快速读取命令 */
    s_command.AddressMode = QSPI_ADDRESS_4_LINES; /* 4个地址线 */
    s_command.DataMode = QSPI_DATA_4_LINES; /* 4个数据线 */
    s_command.DummyCycles = 6; /* 空周期 */

    /* 关闭溢出计数 */
    s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
    s_mem_mapped_cfg.TimeOutPeriod = 0;

    
    if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
    {
        return 1;
    }

    return 0;
}
/*====================================================================================================================*/
/*                                                      本地函数                                                      */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                     End of file                                                    */
/*====================================================================================================================*/
